package com.yx.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yx.constants.HomeConstants;
import com.yx.feign.api.GoodsService;
import com.yx.vo.GoodsType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Classname HomeController
 * @Date 2021/07/10 10:09
 * @Author by yx
 * @Description TODO:
 */
@Controller
@Slf4j
public class HomeController {

    @Autowired
    private GoodsService goodsService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /*
    * 1.一般存放在redis中的数都是JSON字符串,可以跨语言,跨平台,JSON是跨平台
    * 2.查询数据库需要使用分布式锁,查询同样的数据只查询一次数据库
    * 3. 需要解决缓存穿透问题--->使用默认值解决
    * 4.缓存击穿问题--->分布式的双重入锁机制解决
    * */
    @GetMapping({"/index.html","/"})
    public String index(ModelMap modelMap){
        //1.查询redis缓存
        String data = redisTemplate.opsForValue().get(HomeConstants.HOME_GOODS_TYPE_LIST_KEY);
        if (StringUtils.isEmpty(data)){
            //缓存中没有数据,到数据库中查询
            data = queryGoodsTypeList();
        }

        //把JSON字符串转换为list集合
        List<GoodsType> goodsTypeList = JSONObject.parseArray(data, GoodsType.class);
        modelMap.put("goodsTypeList",goodsTypeList);

        return "index";
    }


    /*
    * 从数据库中查询商品类型数据
    * */
    private String queryGoodsTypeList() {
        //1.获取锁
        RLock lock = redissonClient.getLock(HomeConstants.HOME_GOODS_TYPE_LOCK);
        //2.加锁 使用锁的默认时间,超时会自动续命
        lock.lock();
        try {
            //3.重入锁机制,再次查询缓存,
            String data = redisTemplate.opsForValue().get(HomeConstants.HOME_GOODS_TYPE_LIST_KEY);
            if (StringUtils.isEmpty(data)){
                //缓存中没有数据,到数据库中查询
                List<GoodsType> goodsTypeList = goodsService.getGoodsTypeList();

                //创建一个新list集合用于存放商品类型集合,整合父子标签
                List<GoodsType> newGoodsTypeList = new ArrayList<>();
                // 查询并存储一级标签
                for (GoodsType goodsType : goodsTypeList) {
                    if (goodsType.getGoodsTypePid()==-1){
                        newGoodsTypeList.add(goodsType);
                    }
                }

                //查询并存储二级标签
                for (GoodsType fatherType : newGoodsTypeList) {
                    for (GoodsType childType : goodsTypeList) {
                        if (childType.getGoodsTypePid().equals(fatherType.getId())){
                            // 将该子类标签存入父类标签
                            fatherType.getChildrenList().add(childType);
                        }
                    }
                }

                //将查询并封装好的数剧存入redis
                data = JSON.toJSONString(newGoodsTypeList);

                if (!StringUtils.isEmpty(data)){
                    // 查询数据不为空
                    redisTemplate.opsForValue().set(HomeConstants.HOME_GOODS_TYPE_LIST_KEY, data, 10, TimeUnit.DAYS);
                }else {
                    // 数据库中查询的数据为空,即缓存与数据库中都没有数据,此时会发生缓存穿透问题---> 存储一个空字符串解决缓存穿透问题
                    redisTemplate.opsForValue().set(HomeConstants.HOME_GOODS_TYPE_LIST_KEY, "null");

                }
            }
            return data;
        }finally {
            //.释放锁
            lock.unlock();
        }
    }




}
